package com.central.dataManage.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.central.common.constant.CommonConstant;
import com.central.common.enums.DbType;
import com.central.common.model.*;
import com.central.common.service.impl.SuperServiceImpl;
import com.central.dataManage.common.datasourcePlugin.BaseDatasourcePlugin;
import com.central.dataManage.common.datasourcePlugin.DatasourcePluginFactory;
import com.central.dataManage.mapper.DatabaseInfoMapper;
import com.central.dataManage.model.DatabaseInfo;
import com.central.dataManage.service.IDatabaseService;
import com.central.dataManage.service.IDatasourceService;
import com.central.dataManage.service.IDelCacheService;
import com.central.dataManage.service.ITableService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;


/**
 * @author Tindy
 * @date 2021/6/24
 * @describe
 */
@Slf4j
@Service
public class DatabaseServiceImpl extends SuperServiceImpl<DatabaseInfoMapper, DatabaseInfo> implements IDatabaseService {

    @Autowired
    private IDatasourceService datasourceService;
    @Autowired
    private ITableService tableService;
    @Autowired
    private IDelCacheService delCacheService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delByDatasourceId(Long datasourceId) {
        baseMapper.delete(new QueryWrapper<DatabaseInfo>().eq("datasource_id", datasourceId));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result createDatabase(Long datasourceId, String dbName, String reason) {
        DatasourceInfo datasourceInfo = datasourceService.getById(datasourceId);
        if (datasourceInfo != null) {
            BaseDatasourcePlugin datasourcePlugin = DatasourcePluginFactory.getDatasourcePlugin(datasourceInfo);
            try {
                datasourcePlugin.createNewDatabase(dbName);
                DatabaseInfo databaseInfo = new DatabaseInfo();
                databaseInfo.setDatasourceId(datasourceId);
                databaseInfo.setDatasourceType(datasourceInfo.getDatasourceType());
                databaseInfo.setDbName(dbName);
                save(databaseInfo);
                return Result.succeed("创建成功");
            } catch (SQLException ex) {
                return Result.failed("创建失败：" + ex);
            }
        } else {
            return Result.failed("创建失败：数据源不存在");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Result dropDatabase(Long databaseId, String reason) {
        DatabaseInfo databaseInfo = getById(databaseId);
        if (databaseInfo != null) {
            DatasourceInfo datasourceInfo = datasourceService.getById(databaseInfo.getDatasourceId());
            if (datasourceInfo != null) {
                //删除库目录缓存
                delCacheService.delDatabaseList(datasourceInfo.getId());
                BaseDatasourcePlugin datasourcePlugin = DatasourcePluginFactory.getDatasourcePlugin(datasourceInfo);
                try {
                    datasourcePlugin.dropDatabase(databaseInfo.getDbName());
                    tableService.delByDatabaseId(databaseId);
                    removeById(databaseId);
                    return Result.succeed("删除成功");
                } catch (SQLException ex) {
                    return Result.failed("删除失败：" + ex);
                }
            } else {
                return Result.failed("删除失败：数据源不存在");
            }
        } else {
            return Result.failed("删除失败：数据库不存在");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean synchDatabase(Long databaseId) throws SQLException {
        boolean flag = false;
        DatabaseInfo databaseInfo = getById(databaseId);
        if (databaseInfo != null) {
            if(databaseInfo.getDatasourceType()== DbType.KAFKA ||databaseInfo.getDatasourceType()== DbType.HDFS) return false;
            DatasourceInfo datasourceInfo = datasourceService.getById(databaseInfo.getDatasourceId());
            if (datasourceInfo != null) {
                //删除旧元数据
                tableService.delByDatabaseId(databaseId);
                BaseDatasourcePlugin datasourcePlugin = DatasourcePluginFactory.getDatasourcePlugin(datasourceInfo);
                if (datasourcePlugin != null) {
                    Connection conn = datasourcePlugin.getConn();
                    if (conn != null) {
                        try {
                            List<TableInfo> tables = datasourcePlugin.getTables(databaseInfo, conn);
                            for (TableInfo table : tables) {
                                log.info("start synch " + datasourceInfo.getName() + "." + databaseInfo.getDbName() + "." + table.getTableName());
                                List<ColumnInfo> columns = datasourcePlugin.getColumns(databaseInfo, table, conn);
                                table.setColumns(columns);
                                List<IndexInfo> indexs = datasourcePlugin.getIndexs(databaseInfo, table, conn);
                                table.setIndexs(indexs);
                            }
                            tableService.saveBatch(tables);
                            flag = true;
                        } catch (SQLException e) {
                            log.error("close connection fail at DataSourceService::checkConnection()", e);
                            throw e;
                        } finally {
                            conn.close();
                        }
                    }
                }
            }
        }
        return flag;
    }

    @Cacheable(value = "userDbs",key = "#user.username",unless="#result == null")
    @Override
    public DatabaseInfo getUserDb(SysUser user) {
        DatasourceInfo sysDatasource = datasourceService.findSysDatasource();
        if(sysDatasource==null) return null;
        return baseMapper.selectOne(new QueryWrapper<DatabaseInfo>()
                .eq("datasource_id",sysDatasource.getId())
                .eq("db_name", CommonConstant.USER_DB_PREFIX+user.getUsername())
        );
    }

    @Cacheable(value = "proDbs",key = "#user.proName",unless="#result == null")
    @Override
    public DatabaseInfo getProDb(SysUser user) {
        DatasourceInfo sysDatasource = datasourceService.findSysDatasource();
        if(sysDatasource==null) return null;
        return baseMapper.selectOne(new QueryWrapper<DatabaseInfo>()
                .eq("datasource_id",sysDatasource.getId())
                .eq("db_name",CommonConstant.PRO_DB_PREFIX+user.getProName())
        );
    }
}